home *** CD-ROM | disk | FTP | other *** search
/ EuroCD 3 / EuroCD 3.iso / Programming / Python1.4_Source / Lib / multifile.py < prev    next >
Text File  |  1998-06-24  |  3KB  |  129 lines

  1. # A class that makes each part of a multipart message "feel" like an
  2. # ordinary file, as long as you use fp.readline().  Allows recursive
  3. # use, for nested multipart messages.  Probably best used together
  4. # with module mimetools.
  5. #
  6. # Suggested use:
  7. #
  8. # real_fp = open(...)
  9. # fp = MultiFile(real_fp)
  10. #
  11. # "read some lines from fp"
  12. # fp.push(separator)
  13. # while 1:
  14. #    "read lines from fp until it returns an empty string" (A)
  15. #    if not fp.next(): break
  16. # fp.pop()
  17. # "read remaining lines from fp until it returns an empty string"
  18. #
  19. # The latter sequence may be used recursively at (A).
  20. # It is also allowed to use multiple push()...pop() sequences.
  21. # Note that if a nested multipart message is terminated by a separator
  22. # for an outer message, this is not reported, even though it is really
  23. # illegal input.
  24.  
  25. import sys
  26. import string
  27.  
  28. err = sys.stderr.write
  29.  
  30. Error = 'multifile.Error'
  31.  
  32. class MultiFile:
  33.     #
  34.     def __init__(self, fp):
  35.         self.fp = fp
  36.         self.stack = [] # Grows down
  37.         self.level = 0
  38.         self.last = 0
  39.         self.start = self.fp.tell()
  40.         self.posstack = [] # Grows down
  41.     #
  42.     def tell(self):
  43.         if self.level > 0:
  44.             return self.lastpos
  45.         return self.fp.tell() - self.start
  46.     #
  47.     def seek(self, pos):
  48.         if not 0 <= pos <= self.tell() or \
  49.                 self.level > 0 and pos > self.lastpos:
  50.             raise Error, 'bad MultiFile.seek() call'
  51.         self.fp.seek(pos + self.start)
  52.         self.level = 0
  53.         self.last = 0
  54.     #
  55.     def readline(self):
  56.         if self.level > 0: return ''
  57.         line = self.fp.readline()
  58.         if not line:
  59.             self.level = len(self.stack)
  60.             self.last = (self.level > 0)
  61.             if self.last:
  62.                 err('*** Sudden EOF in MultiFile.readline()\n')
  63.             return ''
  64.         if line[:2] <> '--': return line
  65.         n = len(line)
  66.         k = n
  67.         while k > 0 and line[k-1] in string.whitespace: k = k-1
  68.         mark = line[2:k]
  69.         if mark[-2:] == '--': mark1 = mark[:-2]
  70.         else: mark1 = None
  71.         for i in range(len(self.stack)):
  72.             sep = self.stack[i]
  73.             if sep == mark:
  74.                 self.last = 0
  75.                 break
  76.             elif mark1 <> None and sep == mark1:
  77.                 self.last = 1
  78.                 break
  79.         else:
  80.             return line
  81.         # Get here after break out of loop
  82.         self.lastpos = self.tell() - len(line)
  83.         self.level = i+1
  84.         if self.level > 1:
  85.             err('*** Missing endmarker in MultiFile.readline()\n')
  86.         return ''
  87.     #
  88.     def readlines(self):
  89.         list = []
  90.         while 1:
  91.             line = self.readline()
  92.             if not line: break
  93.             list.append(line)
  94.         return list
  95.     #
  96.     def read(self): # Note: no size argument -- read until EOF only!
  97.         return string.joinfields(self.readlines(), '')
  98.     #
  99.     def next(self):
  100.         while self.readline(): pass
  101.         if self.level > 1 or self.last:
  102.             return 0
  103.         self.level = 0
  104.         self.last = 0
  105.         self.start = self.fp.tell()
  106.         return 1
  107.     #
  108.     def push(self, sep):
  109.         if self.level > 0:
  110.             raise Error, 'bad MultiFile.push() call'
  111.         self.stack.insert(0, sep)
  112.         self.posstack.insert(0, self.start)
  113.         self.start = self.fp.tell()
  114.     #
  115.     def pop(self):
  116.         if self.stack == []:
  117.             raise Error, 'bad MultiFile.pop() call'
  118.         if self.level <= 1:
  119.             self.last = 0
  120.         else:
  121.             abslastpos = self.lastpos + self.start
  122.         self.level = max(0, self.level - 1)
  123.         del self.stack[0]
  124.         self.start = self.posstack[0]
  125.         del self.posstack[0]
  126.         if self.level > 0:
  127.             self.lastpos = abslastpos - self.start
  128.     #
  129.